﻿#pragma once

#include <string>
#include <vector>
#include <algorithm>
#include <stdexcept>
#include "../../stringhelper.h"
#include "../../tangible_filesystem.h"

//C# TO C++ CONVERTER NOTE: Forward class declarations:
namespace LibraryEditor { class WTLImage; }

using namespace ManagedSquish;

namespace LibraryEditor
{
    class WTLLibrary
    {
    private:
        bool IsNewVersion = false;

        const std::string _fileName;

    public:
        std::vector<WTLImage*> Images;

    private:
        BinaryReader *_bReader;
        int _count = 0;
        FileStream *_fStream;
        std::vector<int> _indexList;
        bool _initialized = false;

    public:
        virtual ~WTLLibrary()
        {
            delete _bReader;
            delete _fStream;
        }

        bool isNewVersion() const;
        void setNewVersion(bool value);

        WTLLibrary(const std::string &filename);

        void Initialize();

    private:
        void LoadImageInfo();

    public:
        void Close();

        void CheckMImage(int index);

        void ToMLibrary();
    };

    class WTLImage
    {
    private:
        int DataOffset = 0;
        int Index = 0;
        bool IsNewVersion = false;
        unsigned char ImageTextureType = 0;
        unsigned char MaskTextureType = 0;

    public:
        const short Width, Height, X, Y, ShadowX, ShadowY;
        const int Length;

        virtual ~WTLImage()
        {
            delete Image;
            delete MaskImage;
        }

        int getDataOffset() const;

        const unsigned char Shadow;

        int getIndex() const;
        bool isNewVersion() const;
        unsigned char getImageTextureType() const;
        unsigned char getMaskTextureType() const;

    private:
        std::vector<unsigned char> _fBytes;
    public:
        Bitmap *Image;

        const bool HasMask;
        short MaskWidth = 0, MaskHeight = 0, MaskX = 0, MaskY = 0;
        int MaskLength = 0;
    private:
        std::vector<unsigned char> _MaskfBytes;
    public:
        Bitmap *MaskImage;

        WTLImage(int index, bool isNewVersion);

        WTLImage(int index, bool isNewVersion, BinaryReader *bReader);

//C# TO C++ CONVERTER TODO TASK: C# 'unsafe' code is not converted by C# to C++ Converter:
//        public unsafe void CreateTexture(BinaryReader bReader)
//        {
//            Image = ReadImage(bReader, Length, Width, Height, ImageTextureType);
//            if (HasMask)
//            {
//                if (IsNewVersion)
//                {
//                    MaskWidth = Width;
//                    MaskHeight = Height;
//                    MaskX = X;
//                    MaskY = Y;
//                    MaskLength = bReader.ReadInt32();
//                }
//                else
//                {
//                    MaskWidth = bReader.ReadInt16();
//                    MaskHeight = bReader.ReadInt16();
//                    MaskX = bReader.ReadInt16();
//                    MaskY = bReader.ReadInt16();
//                    bReader.ReadInt16(); //mask shadow x
//                    bReader.ReadInt16(); //mask shadow y
//                    MaskLength = bReader.ReadByte() | bReader.ReadByte() << 8 | bReader.ReadByte() << 16;
//                    bReader.ReadByte(); //mask shadow
//                }
//
//                MaskImage = ReadImage(bReader, MaskLength, MaskWidth, MaskHeight, MaskTextureType);
//            }
//        }

//C# TO C++ CONVERTER TODO TASK: C# 'unsafe' code is not converted by C# to C++ Converter:
//        private unsafe Bitmap DecompressV1Texture(BinaryReader bReader, int imageLength, short outputWidth, short outputHeight)
//        {
//            const int size = 8;
//            int offset = 0, blockOffSet = 0;
//            List<byte> countList = new List<byte>();
//            int tWidth = 2;
//
//            while (tWidth < Width)
//                tWidth *= 2;
//
//            _fBytes = bReader.ReadBytes(imageLength);
//
//            Bitmap output = new Bitmap(outputWidth, outputHeight);
//            if (_fBytes.Length != imageLength)
//                return nullptr;
//            BitmapData data = output.LockBits(new Rectangle(0, 0, outputWidth, outputHeight), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
//            byte * pixels = (byte * )data.Scan0;
//            int cap = outputWidth * outputHeight * 4;
//            int currentx = 0;
//
//            while (blockOffSet < imageLength)
//            {
//                countList.Clear();
//                for (int i = 0; i < 8; i++)
//                    countList.Add(_fBytes[blockOffSet++]);
//
//                for (int i = 0; i < countList.Count; i++)
//                {
//                    int count = countList[i];
//
//                    if (i % 2 == 0)
//                    {
//                        if (currentx >= tWidth)
//                            currentx -= tWidth;
//
//                        for (int off = 0; off < count; off++)
//                        {
//                            if (currentx < outputWidth)
//                                offset++;
//
//                            currentx += 4;
//
//                            if (currentx >= tWidth)
//                                currentx -= tWidth;
//                        }
//                        continue;
//                    }
//
//                    for (int c = 0; c < count; c++)
//                    {
//                        if (blockOffSet >= _fBytes.Length)
//                            break;
//
//                        byte[] newPixels = new byte[64];
//                        byte[] block = new byte[size];
//
//                        Array.Copy(_fBytes, blockOffSet, block, 0, size);
//                        blockOffSet += size;
//                        DecompressBlock(newPixels, block);
//
//                        int pixelOffSet = 0;
//                        byte[] sourcePixel = new byte[4];
//
//                        for (int py = 0; py < 4; py++)
//                        {
//                            for (int px = 0; px < 4; px++)
//                            {
//                                int blockx = offset % (outputWidth / 4);
//                                int blocky = offset / (outputWidth / 4);
//
//                                int x = blockx * 4;
//                                int y = blocky * 4;
//
//                                int destPixel = ((y + py) * outputWidth) * 4 + (x + px) * 4;
//
//                                Array.Copy(newPixels, pixelOffSet, sourcePixel, 0, 4);
//                                pixelOffSet += 4;
//
//                                if (destPixel + 4 > cap)
//                                    break;
//                                for (int pc = 0; pc < 4; pc++)
//                                    pixels[destPixel + pc] = sourcePixel[pc];
//                            }
//                        }
//                        offset++;
//                        if (currentx >= outputWidth)
//                            currentx -= outputWidth;
//                        currentx += 4;
//                    }
//                }
//            }
//
//            output.UnlockBits(data);
//            return output;
//        }


//C# TO C++ CONVERTER TODO TASK: C# 'unsafe' code is not converted by C# to C++ Converter:
//        private unsafe Bitmap DecompressV2Texture(BinaryReader bReader, int imageLength, short outputWidth, short outputHeight, byte textureType)
//        {
//            var buffer = bReader.ReadBytes(imageLength);
//
//            int w = Width + (4 - Width % 4) % 4;
//            int a = 1;
//            while (true)
//            {
//                a *= 2;
//                if (a >= w)
//                {
//                    w = a;
//                    break;
//                }
//            }
//            int h = Height + (4 - Height % 4) % 4;
//            int e = w * h / 2;
//
//            SquishFlags type;
//            switch (textureType)
//            {
//                case 0:
//                case 1:
//                    type = SquishFlags.Dxt1;
//                    break;
//                case 3:
//                    type = SquishFlags.Dxt3;
//                    break;
//                case 5:
//                    type = SquishFlags.Dxt5;
//                    break;
//                default:
//                    throw new NotImplementedException();
//            }
//
//
//            var decompressedBuffer = Ionic.Zlib.DeflateStream.UncompressBuffer(buffer);
//
//            var bitmap = new Bitmap(w, h);
//
//            BitmapData data = bitmap.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.WriteOnly, PixelFormat.Format32bppRgb);
//
//            fixed (byte * source = decompressedBuffer)
//                Squish.DecompressImage(data.Scan0, w, h, (IntPtr)source, type);
//
//            byte * dest = (byte * )data.Scan0;
//
//            for (int i = 0; i < w * h * 4; i += 4)
//            {
//                //Reverse Red/Blue
//                byte b = dest[i];
//                dest[i] = dest[i + 2];
//                dest[i + 2] = b;
//            }
//
//            bitmap.UnlockBits(data);
//
//            Rectangle cloneRect = new Rectangle(0, 0, outputWidth, outputHeight);
//            PixelFormat format = bitmap.PixelFormat;
//            Bitmap cloneBitmap = bitmap.Clone(cloneRect, format);
//
//            return cloneBitmap;
//        }

//C# TO C++ CONVERTER TODO TASK: C# 'unsafe' code is not converted by C# to C++ Converter:
//        public unsafe Bitmap ReadImage(BinaryReader bReader, int imageLength, short outputWidth, short outputHeight, byte textureType)
//        {
//            return IsNewVersion ? DecompressV2Texture(bReader, imageLength, outputWidth, outputHeight, textureType) : DecompressV1Texture(bReader, imageLength, outputWidth, outputHeight);
//        }

    private:
        static void DecompressBlock(std::vector<unsigned char> &newPixels, std::vector<unsigned char> &block);

        static int Unpack(std::vector<unsigned char> &packed, int srcOffset, std::vector<unsigned char> &colour, int dstOffSet);
    };
}
